Fix Bug 30240 - std::string: append(first, last) error when aliasing. Add test cases for append/insert/assign/replace while we're at it, and fix a similar bug in insert. git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@280643 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/string b/include/string index 53ddf5e..cfae0c8 100644 --- a/include/string +++ b/include/string
@@ -1998,7 +1998,7 @@ >::type basic_string<_CharT, _Traits, _Allocator>::assign(_InputIterator __first, _InputIterator __last) { - basic_string __temp(__first, __last, __alloc()); + const basic_string __temp(__first, __last, __alloc()); assign(__temp.data(), __temp.size()); return *this; } @@ -2151,11 +2151,17 @@ >::type basic_string<_CharT, _Traits, _Allocator>::append(_InputIterator __first, _InputIterator __last) { - basic_string __temp (__first, __last, __alloc()); + const basic_string __temp (__first, __last, __alloc()); append(__temp.data(), __temp.size()); return *this; } +template <typename _Tp> +bool __ptr_in_range (const _Tp* __p, const _Tp* __first, const _Tp* __last) +{ + return __first <= __p && __p < __last; +} + template <class _CharT, class _Traits, class _Allocator> template<class _ForwardIterator> typename enable_if @@ -2171,13 +2177,21 @@ size_type __n = static_cast<size_type>(_VSTD::distance(__first, __last)); if (__n) { - if (__cap - __sz < __n) - __grow_by(__cap, __sz + __n - __cap, __sz, __sz, 0); - pointer __p = __get_pointer() + __sz; - for (; __first != __last; ++__p, ++__first) - traits_type::assign(*__p, *__first); - traits_type::assign(*__p, value_type()); - __set_size(__sz + __n); + if ( __ptr_in_range(&*__first, data(), data() + size())) + { + const basic_string __temp (__first, __last, __alloc()); + append(__temp.data(), __temp.size()); + } + else + { + if (__cap - __sz < __n) + __grow_by(__cap, __sz + __n - __cap, __sz, __sz, 0); + pointer __p = __get_pointer() + __sz; + for (; __first != __last; ++__p, ++__first) + traits_type::assign(*__p, *__first); + traits_type::assign(*__p, value_type()); + __set_size(__sz + __n); + } } return *this; } @@ -2299,7 +2313,7 @@ "string::insert(iterator, range) called with an iterator not" " referring to this string"); #endif - basic_string __temp(__first, __last, __alloc()); + const basic_string __temp(__first, __last, __alloc()); return insert(__pos, __temp.data(), __temp.data() + __temp.size()); } @@ -2319,11 +2333,17 @@ " referring to this string"); #endif size_type __ip = static_cast<size_type>(__pos - begin()); - size_type __sz = size(); - size_type __cap = capacity(); size_type __n = static_cast<size_type>(_VSTD::distance(__first, __last)); if (__n) { + if ( __ptr_in_range(&*__first, data(), data() + size())) + { + const basic_string __temp(__first, __last, __alloc()); + return insert(__pos, __temp.data(), __temp.data() + __temp.size()); + } + + size_type __sz = size(); + size_type __cap = capacity(); value_type* __p; if (__cap - __sz >= __n) { @@ -2523,7 +2543,7 @@ basic_string<_CharT, _Traits, _Allocator>::replace(const_iterator __i1, const_iterator __i2, _InputIterator __j1, _InputIterator __j2) { - basic_string __temp(__j1, __j2, __alloc()); + const basic_string __temp(__j1, __j2, __alloc()); return this->replace(__i1, __i2, __temp); } diff --git a/test/std/strings/basic.string/string.modifiers/string_append/iterator.pass.cpp b/test/std/strings/basic.string/string.modifiers/string_append/iterator.pass.cpp index 55fc63d..8c54a38 100644 --- a/test/std/strings/basic.string/string.modifiers/string_append/iterator.pass.cpp +++ b/test/std/strings/basic.string/string.modifiers/string_append/iterator.pass.cpp
@@ -178,4 +178,21 @@ test_exceptions(S(), TIter(s, s+10, 6, TIter::TAComparison), TIter()); } #endif + + { // test appending to self + typedef std::string S; + S s_short = "123/"; + S s_long = "Lorem ipsum dolor sit amet, consectetur/"; + + s_short.append(s_short.begin(), s_short.end()); + assert(s_short == "123/123/"); + s_short.append(s_short.begin(), s_short.end()); + assert(s_short == "123/123/123/123/"); + s_short.append(s_short.begin(), s_short.end()); + assert(s_short == "123/123/123/123/123/123/123/123/"); + + s_long.append(s_long.begin(), s_long.end()); + assert(s_long == "Lorem ipsum dolor sit amet, consectetur/Lorem ipsum dolor sit amet, consectetur/"); + } + } diff --git a/test/std/strings/basic.string/string.modifiers/string_append/pointer.pass.cpp b/test/std/strings/basic.string/string.modifiers/string_append/pointer.pass.cpp index 7c45068..e658d0f 100644 --- a/test/std/strings/basic.string/string.modifiers/string_append/pointer.pass.cpp +++ b/test/std/strings/basic.string/string.modifiers/string_append/pointer.pass.cpp
@@ -61,4 +61,20 @@ S("1234567890123456789012345678901234567890")); } #endif + + { // test appending to self + typedef std::string S; + S s_short = "123/"; + S s_long = "Lorem ipsum dolor sit amet, consectetur/"; + + s_short.append(s_short.c_str()); + assert(s_short == "123/123/"); + s_short.append(s_short.c_str()); + assert(s_short == "123/123/123/123/"); + s_short.append(s_short.c_str()); + assert(s_short == "123/123/123/123/123/123/123/123/"); + + s_long.append(s_long.c_str()); + assert(s_long == "Lorem ipsum dolor sit amet, consectetur/Lorem ipsum dolor sit amet, consectetur/"); + } } diff --git a/test/std/strings/basic.string/string.modifiers/string_append/pointer_size.pass.cpp b/test/std/strings/basic.string/string.modifiers/string_append/pointer_size.pass.cpp index 6c594eb..25a4526 100644 --- a/test/std/strings/basic.string/string.modifiers/string_append/pointer_size.pass.cpp +++ b/test/std/strings/basic.string/string.modifiers/string_append/pointer_size.pass.cpp
@@ -70,4 +70,20 @@ S("1234567890123456789012345678901234567890")); } #endif + + { // test appending to self + typedef std::string S; + S s_short = "123/"; + S s_long = "Lorem ipsum dolor sit amet, consectetur/"; + + s_short.append(s_short.data(), s_short.size()); + assert(s_short == "123/123/"); + s_short.append(s_short.data(), s_short.size()); + assert(s_short == "123/123/123/123/"); + s_short.append(s_short.data(), s_short.size()); + assert(s_short == "123/123/123/123/123/123/123/123/"); + + s_long.append(s_long.data(), s_long.size()); + assert(s_long == "Lorem ipsum dolor sit amet, consectetur/Lorem ipsum dolor sit amet, consectetur/"); + } } diff --git a/test/std/strings/basic.string/string.modifiers/string_assign/iterator.pass.cpp b/test/std/strings/basic.string/string.modifiers/string_assign/iterator.pass.cpp index e6a5751..0d3dac7 100644 --- a/test/std/strings/basic.string/string.modifiers/string_assign/iterator.pass.cpp +++ b/test/std/strings/basic.string/string.modifiers/string_assign/iterator.pass.cpp
@@ -179,4 +179,21 @@ test_exceptions(S(), TIter(s, s+10, 6, TIter::TAComparison), TIter()); } #endif + + { // test assigning to self + typedef std::string S; + S s_short = "123/"; + S s_long = "Lorem ipsum dolor sit amet, consectetur/"; + + s_short.assign(s_short.begin(), s_short.end()); + assert(s_short == "123/"); + s_short.assign(s_short.begin() + 2, s_short.end()); + assert(s_short == "3/"); + + s_long.assign(s_long.begin(), s_long.end()); + assert(s_long == "Lorem ipsum dolor sit amet, consectetur/"); + + s_long.assign(s_long.begin() + 30, s_long.end()); + assert(s_long == "nsectetur/"); + } } diff --git a/test/std/strings/basic.string/string.modifiers/string_assign/pointer.pass.cpp b/test/std/strings/basic.string/string.modifiers/string_assign/pointer.pass.cpp index 386dee6..1a509e7 100644 --- a/test/std/strings/basic.string/string.modifiers/string_assign/pointer.pass.cpp +++ b/test/std/strings/basic.string/string.modifiers/string_assign/pointer.pass.cpp
@@ -61,4 +61,18 @@ S("12345678901234567890")); } #endif + + { // test assignment to self + typedef std::string S; + S s_short = "123/"; + S s_long = "Lorem ipsum dolor sit amet, consectetur/"; + + s_short.assign(s_short.c_str()); + assert(s_short == "123/"); + s_short.assign(s_short.c_str() + 2); + assert(s_short == "3/"); + + s_long.assign(s_long.c_str() + 30); + assert(s_long == "nsectetur/"); + } } diff --git a/test/std/strings/basic.string/string.modifiers/string_assign/pointer_size.pass.cpp b/test/std/strings/basic.string/string.modifiers/string_assign/pointer_size.pass.cpp index 0eeb926..b657127 100644 --- a/test/std/strings/basic.string/string.modifiers/string_assign/pointer_size.pass.cpp +++ b/test/std/strings/basic.string/string.modifiers/string_assign/pointer_size.pass.cpp
@@ -70,4 +70,20 @@ S("12345678901234567890")); } #endif + { // test assign to self + typedef std::string S; + S s_short = "123/"; + S s_long = "Lorem ipsum dolor sit amet, consectetur/"; + + s_short.assign(s_short.data(), s_short.size()); + assert(s_short == "123/"); + s_short.assign(s_short.data() + 2, s_short.size() - 2); + assert(s_short == "3/"); + + s_long.assign(s_long.data(), s_long.size()); + assert(s_long == "Lorem ipsum dolor sit amet, consectetur/"); + + s_long.assign(s_long.data() + 2, 8 ); + assert(s_long == "rem ipsu"); + } } diff --git a/test/std/strings/basic.string/string.modifiers/string_insert/iter_iter_iter.pass.cpp b/test/std/strings/basic.string/string.modifiers/string_insert/iter_iter_iter.pass.cpp index bbae394..1b5baf4 100644 --- a/test/std/strings/basic.string/string.modifiers/string_insert/iter_iter_iter.pass.cpp +++ b/test/std/strings/basic.string/string.modifiers/string_insert/iter_iter_iter.pass.cpp
@@ -169,4 +169,21 @@ assert(false); } #endif + + { // test inserting into self + typedef std::string S; + S s_short = "123/"; + S s_long = "Lorem ipsum dolor sit amet, consectetur/"; + + s_short.insert(s_short.begin(), s_short.begin(), s_short.end()); + assert(s_short == "123/123/"); + s_short.insert(s_short.begin(), s_short.begin(), s_short.end()); + assert(s_short == "123/123/123/123/"); + s_short.insert(s_short.begin(), s_short.begin(), s_short.end()); + assert(s_short == "123/123/123/123/123/123/123/123/"); + + s_long.insert(s_long.begin(), s_long.begin(), s_long.end()); + assert(s_long == "Lorem ipsum dolor sit amet, consectetur/Lorem ipsum dolor sit amet, consectetur/"); + } + } diff --git a/test/std/strings/basic.string/string.modifiers/string_insert/size_pointer.pass.cpp b/test/std/strings/basic.string/string.modifiers/string_insert/size_pointer.pass.cpp index faab5bd..3b1c2cb 100644 --- a/test/std/strings/basic.string/string.modifiers/string_insert/size_pointer.pass.cpp +++ b/test/std/strings/basic.string/string.modifiers/string_insert/size_pointer.pass.cpp
@@ -210,4 +210,20 @@ test(S("abcdefghijklmnopqrst"), 21, "12345678901234567890", S("can't happen")); } #endif + + { // test inserting into self + typedef std::string S; + S s_short = "123/"; + S s_long = "Lorem ipsum dolor sit amet, consectetur/"; + + s_short.insert(0, s_short.c_str()); + assert(s_short == "123/123/"); + s_short.insert(0, s_short.c_str()); + assert(s_short == "123/123/123/123/"); + s_short.insert(0, s_short.c_str()); + assert(s_short == "123/123/123/123/123/123/123/123/"); + + s_long.insert(0, s_long.c_str()); + assert(s_long == "Lorem ipsum dolor sit amet, consectetur/Lorem ipsum dolor sit amet, consectetur/"); + } } diff --git a/test/std/strings/basic.string/string.modifiers/string_insert/size_pointer_size.pass.cpp b/test/std/strings/basic.string/string.modifiers/string_insert/size_pointer_size.pass.cpp index 30d3df9..554b93c 100644 --- a/test/std/strings/basic.string/string.modifiers/string_insert/size_pointer_size.pass.cpp +++ b/test/std/strings/basic.string/string.modifiers/string_insert/size_pointer_size.pass.cpp
@@ -691,4 +691,20 @@ test(S("abcdefghijklmnopqrst"), 21, "12345678901234567890", 20, S("can't happen")); } #endif + + { // test inserting into self + typedef std::string S; + S s_short = "123/"; + S s_long = "Lorem ipsum dolor sit amet, consectetur/"; + + s_short.insert(0, s_short.data(), s_short.size()); + assert(s_short == "123/123/"); + s_short.insert(0, s_short.data(), s_short.size()); + assert(s_short == "123/123/123/123/"); + s_short.insert(0, s_short.data(), s_short.size()); + assert(s_short == "123/123/123/123/123/123/123/123/"); + + s_long.insert(0, s_long.data(), s_long.size()); + assert(s_long == "Lorem ipsum dolor sit amet, consectetur/Lorem ipsum dolor sit amet, consectetur/"); + } } diff --git a/test/std/strings/basic.string/string.modifiers/string_replace/iter_iter_iter_iter.pass.cpp b/test/std/strings/basic.string/string.modifiers/string_replace/iter_iter_iter_iter.pass.cpp index cc37e79..abf1521 100644 --- a/test/std/strings/basic.string/string.modifiers/string_replace/iter_iter_iter_iter.pass.cpp +++ b/test/std/strings/basic.string/string.modifiers/string_replace/iter_iter_iter_iter.pass.cpp
@@ -1007,4 +1007,20 @@ test_exceptions(S("abcdefghijklmnopqrst"), 10, 5, TIter(s, s+10, 6, TIter::TAComparison), TIter()); } #endif + + { // test replacing into self + typedef std::string S; + S s_short = "123/"; + S s_long = "Lorem ipsum dolor sit amet, consectetur/"; + + s_short.replace(s_short.begin(), s_short.begin(), s_short.begin(), s_short.end()); + assert(s_short == "123/123/"); + s_short.replace(s_short.begin(), s_short.begin(), s_short.begin(), s_short.end()); + assert(s_short == "123/123/123/123/"); + s_short.replace(s_short.begin(), s_short.begin(), s_short.begin(), s_short.end()); + assert(s_short == "123/123/123/123/123/123/123/123/"); + + s_long.replace(s_long.begin(), s_long.begin(), s_long.begin(), s_long.end()); + assert(s_long == "Lorem ipsum dolor sit amet, consectetur/Lorem ipsum dolor sit amet, consectetur/"); + } } diff --git a/test/std/strings/basic.string/string.modifiers/string_replace/iter_iter_pointer.pass.cpp b/test/std/strings/basic.string/string.modifiers/string_replace/iter_iter_pointer.pass.cpp index 730fc1a..20d185f 100644 --- a/test/std/strings/basic.string/string.modifiers/string_replace/iter_iter_pointer.pass.cpp +++ b/test/std/strings/basic.string/string.modifiers/string_replace/iter_iter_pointer.pass.cpp
@@ -282,4 +282,20 @@ test2<S>(); } #endif + + { // test replacing into self + typedef std::string S; + S s_short = "123/"; + S s_long = "Lorem ipsum dolor sit amet, consectetur/"; + + s_short.replace(s_short.begin(), s_short.begin(), s_short.c_str()); + assert(s_short == "123/123/"); + s_short.replace(s_short.begin(), s_short.begin(), s_short.c_str()); + assert(s_short == "123/123/123/123/"); + s_short.replace(s_short.begin(), s_short.begin(), s_short.c_str()); + assert(s_short == "123/123/123/123/123/123/123/123/"); + + s_long.replace(s_long.begin(), s_long.begin(), s_long.c_str()); + assert(s_long == "Lorem ipsum dolor sit amet, consectetur/Lorem ipsum dolor sit amet, consectetur/"); + } } diff --git a/test/std/strings/basic.string/string.modifiers/string_replace/iter_iter_pointer_size.pass.cpp b/test/std/strings/basic.string/string.modifiers/string_replace/iter_iter_pointer_size.pass.cpp index 4a910e4..59d34fe 100644 --- a/test/std/strings/basic.string/string.modifiers/string_replace/iter_iter_pointer_size.pass.cpp +++ b/test/std/strings/basic.string/string.modifiers/string_replace/iter_iter_pointer_size.pass.cpp
@@ -972,4 +972,20 @@ test8<S>(); } #endif + + { // test replacing into self + typedef std::string S; + S s_short = "123/"; + S s_long = "Lorem ipsum dolor sit amet, consectetur/"; + + s_short.replace(s_short.begin(), s_short.begin(), s_short.data(), s_short.size()); + assert(s_short == "123/123/"); + s_short.replace(s_short.begin(), s_short.begin(), s_short.data(), s_short.size()); + assert(s_short == "123/123/123/123/"); + s_short.replace(s_short.begin(), s_short.begin(), s_short.data(), s_short.size()); + assert(s_short == "123/123/123/123/123/123/123/123/"); + + s_long.replace(s_long.begin(), s_long.begin(), s_long.data(), s_long.size()); + assert(s_long == "Lorem ipsum dolor sit amet, consectetur/Lorem ipsum dolor sit amet, consectetur/"); + } }